package nx.simple3d.gui;

import java.awt.BorderLayout;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.io.File;
import java.io.FileNotFoundException;

import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.filechooser.FileFilter;

import nx.simple3d.data.Camera;
import nx.simple3d.data.Mesh;
import nx.simple3d.data.ObjFile;
import nx.simple3d.main.Core;


public class Window extends JFrame implements MouseMotionListener, MouseListener, ActionListener{

  private static final long serialVersionUID = 8379298402221575482L;
  private Camera camera;
  private Core core;
  private Point lastMousePosition;
  private Nx3DCanvas nx3DCanvas;
  private JMenuBar menuBar;
  private JMenu fileMenu;
  private JMenuItem fileMenuItemLoad;

  public Window(Core core){
    super();
    this.core = core;
    this.camera = core.getWorld().getCamera();
    initialize();
  }
  
  private void initialize(){
    setTitle("NX Simple 3D");
    setSize(800, 600);
    getContentPane().add(getMainMenuBar(), BorderLayout.NORTH);
    getContentPane().add(get3DCanvas(), BorderLayout.CENTER);
    setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
  }
    
  @Override
  public void setVisible(boolean b) {
    super.setVisible(b);
    nx3DCanvas.createBufferStrategy(2);
  }

  public Nx3DCanvas get3DCanvas(){
    if(nx3DCanvas == null){
      nx3DCanvas = new Nx3DCanvas(camera);
      nx3DCanvas.addMouseMotionListener(this);
      nx3DCanvas.addMouseListener(this);
    }
    return nx3DCanvas;
  }
  
  private JMenuBar getMainMenuBar(){
    if(menuBar == null){
      menuBar = new JMenuBar();
      menuBar.add(getFileMenu());
    }
    return menuBar;
  }
  
  private JMenu getFileMenu(){
    if(fileMenu == null){
      fileMenu = new JMenu("File");
      fileMenu.add(getFileMenuLoadItem());
    }
    return fileMenu;
  }
  
  private JMenuItem getFileMenuLoadItem(){
    if(fileMenuItemLoad == null){
      fileMenuItemLoad = new JMenuItem("Load Obj...");
      fileMenuItemLoad.setActionCommand("LOAD");
      fileMenuItemLoad.addActionListener(this);
    }
    return fileMenuItemLoad;
  }
  
  @Override
  public void mouseDragged(MouseEvent e) {
    if(lastMousePosition == null)
      return;
    Point mouse = e.getPoint();
    
    if((e.getModifiersEx() & MouseEvent.BUTTON1_DOWN_MASK) != 0){
      double[] translation = new double[3];
      translation[2] = (double)(lastMousePosition.x - mouse.x) / 50d;
      translation[1] = (double)(mouse.y - lastMousePosition.y) / 50d;
      camera.getTransformation().translate(translation);
    }
    
    if((e.getModifiersEx() & MouseEvent.BUTTON2_DOWN_MASK) != 0){
      double[] translation = new double[3];
      translation[2] = (double)(lastMousePosition.x - mouse.x) / 50d;
      translation[0] = (double)(lastMousePosition.y - mouse.y) / 50d;
      camera.getTransformation().translate(translation);
    }
    
    if((e.getModifiersEx() & MouseEvent.BUTTON3_DOWN_MASK) != 0){
      camera.getTransformation().rotateY((double)(lastMousePosition.x - mouse.x) / 500d);
      camera.getTransformation().rotateZ((double)(lastMousePosition.y - mouse.y) / 500d);
    }
        
    lastMousePosition = e.getPoint();
  }

  @Override
  public void mouseMoved(MouseEvent e) {}

  @Override
  public void mouseClicked(MouseEvent e) {}

  @Override
  public void mousePressed(MouseEvent e) {
    lastMousePosition = e.getPoint();
  }

  @Override
  public void mouseReleased(MouseEvent e) {}

  @Override
  public void mouseEntered(MouseEvent e) {}

  @Override
  public void mouseExited(MouseEvent e) {}

  @Override
  public void actionPerformed(ActionEvent e) {
    if(e.getActionCommand().equals("LOAD")){
      JFileChooser fileChooser = new JFileChooser();
      fileChooser.setFileFilter(new FileFilter() {        
        @Override
        public String getDescription() {
          return "Wavefront OBJ";
        }        
        @Override
        public boolean accept(File f) {
          int ext = f.getName().lastIndexOf('.');
          if(ext == -1) return true;
          return f.getName().substring(f.getName().lastIndexOf('.')).equalsIgnoreCase(".obj");
        }
      });
      if(fileChooser.showOpenDialog(this) == JFileChooser.APPROVE_OPTION){
        try {
          ObjFile objFile = new ObjFile(fileChooser.getSelectedFile());
          Mesh objMesh = objFile.createMesh();
          
          double[] randomVec = new double[3];
          randomVec[0] = Math.random() * 5;
          randomVec[1] = Math.random() * 5;
          randomVec[2] = Math.random() * 5;
          objMesh.getTransformation().translate(randomVec);
          objMesh.getTransformation().rotateY(Math.random());
          objMesh.getTransformation().rotateX(Math.random());
          objMesh.getTransformation().rotateZ(Math.random());
          
          core.getEngine().stopEngine();
          try {
            Thread.sleep(200);
          }
          catch (InterruptedException e1) {
            e1.printStackTrace();
          }          
          core.getWorld().getMeshes().add(objMesh);
          core.getEngine().startEngine();
        }
        catch (FileNotFoundException e1) {
          e1.printStackTrace();
        }
      }
    }
  }
}
